﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace NetCommand
{
    public interface INetCommand
    {
        
    }

    /// <summary>
    /// 命令成员位置标识
    /// </summary>
    public sealed class SerializeFieldAttribute : System.Attribute
    {
        private int m_nSize = 1;
        public int Size { get { return m_nSize; } set { m_nSize = value; } }
    }

    [Serializable]
    public struct NetCommandHeader
    {
        public UInt16 CMD_ID;               // 命令地址 命令标识
        public byte CMD_FRONT_ID;           // 命令前导码，识别是否为命令
        public UInt16 CMD_AREA_ID;          // 站点区域邮编
        public byte CMD_DEVICE_ID;          // 设备码
        public byte CMD_R_W;                // 读写标识位
        public byte CMD_LEN;                // 命令长度

        public override string ToString()
        {
            string str = "Header : \r\n{ \r\n" +
                "\tCMD_ID\t\t:" + CMD_ID.ToString() + "\r\n" +
                "\tCMD_FRONT_ID\t:" + CMD_FRONT_ID.ToString() + "\r\n" +
                "\tCMD_AREA_ID\t:" + CMD_AREA_ID.ToString() + "\r\n" +
                "\tCMD_DEVICE_ID\t:" + CMD_DEVICE_ID.ToString() + "\r\n" +
                "\tCMD_R_W\t\t:" + CMD_R_W.ToString() + "\r\n" +
                "\tCMD_LEN\t\t:" + CMD_LEN.ToString() + "\r\n}\r\n";
            return str;
        }

        public static int getSize()
        {
            return 8;
            /*
              1          // 命令码
            + 2          // 站点区域邮编
            + 1          // 设备码
            + 1          // 读写标识位
            + 1          // 命令长度
            + 2;         // 命令地址
        ----------------
            = 8
             */
        }

        public static NetCommandHeader MakeHeader()
        {
            NetCommandHeader header = new NetCommandHeader();

            return header;
        }
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class NetStruct : INetCommand
    {
        public override string ToString()
        {
            string str = "\r\n\t{\n";
            foreach (var field in GetType().GetFields())
            {
                object[] fieldattrs = field.GetCustomAttributes(false);
                if (fieldattrs.Length > 0)
                {
                    SerializeFieldAttribute attr = (SerializeFieldAttribute)fieldattrs[0];
                    if (attr == null)
                    {
                        continue;
                    }
                    if (field.FieldType.Name == "List`1")
                    {
                        IList list = field.GetValue(this) as IList;
                        for (int i = 0; i < list.Count; i++)
                        {
                            str += list[i].ToString() + "\n";
                        }
                    }
                    else
                    {
                        str += "\t\t" + field.Name + "\t:" + field.GetValue(this) + "\n";
                    }
                }
            }
            str += "\r\n\t}";
            return str;
        }
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class NetCommand : INetCommand
    {
        public NetCommandHeader Header;
        public UInt16 _CRC = 0;
        public UInt16 ErrorCode = 0;
        public int R_W;
        private byte size = 0;
        public int getSize()
        {
            return size;
        }
        public virtual byte CommandType
        {
            get;
            set;
        }

        public UInt16 SpareByte;// 备用

        public override string ToString()
        {
            string str = Header.ToString() + "\r\nBody : \r\n{\r\n";
            foreach (var field in GetType().GetFields())
            {
                object[] fieldattrs = field.GetCustomAttributes(false);
                if (fieldattrs.Length > 0)
                {
                    SerializeFieldAttribute attr = (SerializeFieldAttribute)fieldattrs[0];
                    if (attr == null)
                    {
                        continue;
                    }
                    if (field.FieldType.Name == "List`1")
                    {
                        IList list = field.GetValue(this) as IList;
                        str += "\t" + field.Name + " : \n\t[\n";
                        for (int i = 0; i < list.Count; i++)
                        {
                            str += "\t\t" + list[i].ToString() + "\n";
                        }
                        str += "\t]\n";
                    }
                    else
                    {
                        str += "\t" + field.Name + "\t:" + field.GetValue(this) + "\r\n";
                    }
                }
            }
            str += "\r\n}\r\n";
            return str;
        }
        
        public byte[] genCRC()
        {
            byte[] bMsg = CommandTranslator.Instance.EncodeMessage(this);
            byte[] checkCrc = EncodingTools.CopyBytes(bMsg, 0, bMsg.Length - 2);
            UInt16 crc = CRC.crc16(checkCrc);
            return EncodingTools.shortToBytes(crc);
        }
        
    }

    [StructLayout(LayoutKind.Sequential)]
    public class C2S_Command : NetCommand
    {
        public override byte CommandType
        {
            get
            {
                return NetCommon.C2S_COMMAND_TYPE;
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public class S2C_Command : NetCommand
    {
        public override byte CommandType
        {
            get
            {
                return NetCommon.S2C_COMMAND_TYPE;
            }
        }
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class D2S_Command : NetCommand
    {
        public override byte CommandType
        {
            get
            {
                return NetCommon.D2S_COMMAND_TYPE;
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public class S2D_Command : NetCommand
    {
        public override byte CommandType
        {
            get
            {
                return NetCommon.S2D_COMMAND_TYPE;
            }
        }
    }
}
